home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
c
/
cserial.zip
/
8250DTR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-04
|
12KB
|
456 lines
/*
* DTR8250.C
*
* NSC8250 DTR Handshake ISR Module
*
* Written for the
*
* Datalight
* Microsoft V 5.x
* TurboC
* &
* Zortech
*
* C Compilers
*
* Copyright (c) John Birchfield 1987, 1988, 1989
*/
#include <stdio.h>
#include "dependnt.h"
#include "queue.h"
#include "8250nsc.h"
#include "8250dtr.h"
#include "timer.h"
#if (!defined (TRUE))
# define TRUE (1)
# define FALSE (0)
#endif
unsigned DTR_PORT_channel; /* Either 1 or 2 for COM1 or COM2 */
char dtr8250_SAVE_int_mask, /* saved interrupt controller mask word */
dtr8250_IER_save = 0, /* Saved off Interrupt Enable Register */
dtr8250_LCR_save = 0, /* Saved off Line Control Register */
dtr8250_MCR_save = 0, /* Saved off Modem Control Register */
dtr8250_DL_lsb = 0, /* Saved off Baud Rate LSB */
dtr8250_DL_msb = 0; /* Saved off Baud Rate MSB */
volatile unsigned DTR_PORT_addr;
volatile char DTR_PORT_status, RCV_disabled = FALSE, XMIT_disabled = TRUE, dtr8250_MSR_reg = 0;
volatile QUEUE *dtr8250_inqueue;
#if (defined (DLC))
extern void outp ();
#endif
#define DISABLE_xmit outbyte (DTR_PORT_addr+IER, RX_enable)
#define ENABLE_xmit outbyte (DTR_PORT_addr+IER, RX_TX_enable)
#define DROPPED_cts ((dtr8250_MSR_reg&0x10)==0)
#define DROPPED_dsr ((dtr8250_MSR_reg&0x20)==0)
#define DROPPED_dtr ((dtr8250_MSR_reg&0x30)!=0x30)
#define ASSERT_dtr outbyte (inbyte (DTR_PORT_addr+MCR)|9, DTR_PORT_addr+MCR)
#define DROP_dtr outbyte (inbyte (DTR_PORT_addr+MCR)&0x0A, DTR_PORT_addr+MCR)
#define ASSERT_rts outbyte (inbyte (DTR_PORT_addr+MCR)|0x0A, DTR_PORT_addr+MCR)
#define DROP_rts outbyte (inbyte (DTR_PORT_addr+MCR)&9, DTR_PORT_addr+MCR)
#define TSRE_bit 0x40
/*
* DTR8250_ISR - This Interrupt Service Routine attached to either COM1
* or COM2. It drives the NSC8250 with Hardware
* Handshaking. i.e. Flow of Control is maintained by
* RTS (Request to Send) CTS (Clear to Send) Logic.
* After installation by Catch_Rt, it catches the
* 8250 interrupts and en_queues incoming characters
* from the Serial Port - and de-queues outgoing
* characters to the Serial Port.
*/
#if (!defined (DLC))
void (interrupt far * dtr_save_vec) (void);
void interrupt far
dtr8250_isr (void)
#else
int
dtr8250_isr ()
#endif
{
int ch;
char test_status;
enable ();
test_status = inbyte ((DTR_PORT_addr + IIR));
do
{
switch (test_status)
{
case IIR_rls:
DTR_PORT_status |= inbyte ((DTR_PORT_addr + LSR));
break;
case IIR_receive:
ch = inbyte (DTR_PORT_addr);
if ((en_queue (dtr8250_inqueue, ch) < 10) && !RCV_disabled)
{
RCV_disabled = TRUE;
DROP_dtr;
}
else
if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
{
RCV_disabled = FALSE;
ASSERT_dtr;
}
break;
case IIR_transmit:
DISABLE_xmit;
break;
case IIR_mstatus:
dtr8250_MSR_reg = inbyte (DTR_PORT_addr + MSR);
if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
{
RCV_disabled = FALSE;
ASSERT_dtr;
}
break;
}
} while ((test_status = inbyte (DTR_PORT_addr + IIR)) != IIR_complete);
disable ();
outbyte (INT_cntrl, EOI_word);
#if (defined (DLC))
return (1);
#endif
}
/*
* DTR8250_INIT - Here we get the address of the 8250 Port
* which corresponds to the channel passed in.
* We then massage the 8259 Interrupt Controller
* calculate the Physical Interrupt and save off
* the 8250's current contents. Then attach the
* nsc8250_interrupt routine to the interrupt and
* return the rt returned index for saving - it's
* needed to terminate the interrupt.
*/
#define DTR8250_STACK_SIZE 1024
int dtr8250_intno;
static int dtr_intmask [] = { 0xef, 0xf7, 0xef, 0xf7 };
/*
* The above 8259 mask bits are determined from the formula
* mask = ~(1 << (5 - PORT_CHANNEL));
* The array assumes that COM3 and COM4 use the same interrupts
* as COM1 and COM2.
*/
static int dtr_intno [] = { 12, 11, 12, 11 };
/*
* The above interrupt number array is based on the algorithm
* dtr8250_intno = (13 - PORT_channel);
*/
void
dtr8250_init (channel, buf_size)
int channel, buf_size;
{
int Dos_address, mask;
DTR_PORT_channel = channel;
dtr8250_inqueue = alloc_queue (buf_size);
Dos_address = (DTR_PORT_channel - 1) * 2;
peekmem (0x40, Dos_address, DTR_PORT_addr);
mask = dtr_intmask [DTR_PORT_channel-1];
dtr8250_SAVE_int_mask = inbyte (INT_mask);
mask &= dtr8250_SAVE_int_mask;
dtr8250_intno = dtr_intno [DTR_PORT_channel-1];
dtr8250_LCR_save = inbyte (DTR_PORT_addr + LCR);
disable ();
outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save | LCR_DLAB);
dtr8250_MCR_save = inbyte (DTR_PORT_addr + MCR);
dtr8250_DL_lsb = inbyte (DTR_PORT_addr);
dtr8250_DL_msb = inbyte (DTR_PORT_addr + 1);
outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save & 0x7F);
dtr8250_IER_save = inbyte (DTR_PORT_addr + IER);
enable ();
#if (defined (DLC))
int_intercept (dtr8250_intno, &dtr8250_isr, DTR8250_STACK_SIZE);
#else
dtr_save_vec = getvect (dtr8250_intno);
setvect (dtr8250_intno, dtr8250_isr);
#endif
DELAY_init ();
outbyte (INT_mask, mask);
}
/*
* DTR8250_TERM - This routine restores the RS232 Vector back to its
* state before DTR8250_INIT was called.
*/
void
dtr8250_term (int restore)
{
disable ();
outbyte (INT_mask, dtr8250_SAVE_int_mask);
if (restore)
{
outbyte (DTR_PORT_addr + LCR, LCR_DLAB);
outbyte (DTR_PORT_addr, dtr8250_DL_lsb);
outbyte (DTR_PORT_addr + 1, dtr8250_DL_msb);
outbyte (DTR_PORT_addr + MCR, dtr8250_MCR_save);
outbyte (DTR_PORT_addr + LCR, 0x7F);
outbyte (DTR_PORT_addr + IER, dtr8250_IER_save);
outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save);
}
#if (defined (DLC))
int_restore (dtr8250_intno);
#else
setvect (dtr8250_intno, dtr_save_vec);
#endif
}
/*
* DTR8250_READ - this routine looks in the RS232hw_inqueue for a character
*
*/
int
dtr8250_read (void)
{
int ch;
disable ();
ch = de_queue (dtr8250_inqueue);
enable ();
return (ch);
}
/*
* DTR8250_TIMED_READ - attempts to read rs232 port - if no char
* available in number of seconds passed
* returns -1
*/
int
dtr8250_timed_read (int sec)
{
int ch;
timer_set ();
while ((ch = dtr8250_read ()) == -1)
if ((timer_read () / 18) > sec)
break;
return (ch);
}
/*
* DTR8250_WRITE - plain vanilla write to the port - check to see that
* the chip may need a kick in the pants before returning
*/
int
dtr8250_write (char ch)
{
while ((inbyte (DTR_PORT_addr + LSR) & TSRE_bit) == 0)
;
dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
if (DROPPED_dtr)
return -1;
outbyte (DTR_PORT_addr, ch);
if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
{
RCV_disabled = FALSE;
ASSERT